package com.xpec.c4.service.module.datacenter.player;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import com.xpec.c4.game.datamanager.BaseDataInfo;
import com.xpec.c4.game.datamanager.DataManager;
import com.xpec.c4.game.datamanager.DataSource;
import com.xpec.c4.game.datamanager.ResultNo;
import com.xpec.c4.game.datamanager.agent.PlayerData;
import com.xpec.c4.game.utility.GUID;
import com.xpec.c4.game.utility.GameUtility;
import com.xpec.c4.service.module.BasicServiceModule;
import com.xpec.c4.service.module.datacenter.DCAsyncCommand;
import com.xpec.c4.service.module.datacenter.DataElement;
import com.xpec.c4.service.module.task.TaskAsyncCommand;


/**
 * 
 * @author yangbingyan
 *
 */
public class PlayerDataManager extends DataManager<DataElement>{
	
	/**
	 * 
	 */
	@SuppressWarnings("unused")
	private static final Log log = LogFactory.getLog(PlayerDataManager.class);

	/**
	 * 
	 * @param module
	 */
	public PlayerDataManager(BasicServiceModule module) {
		super(module);
	}

	
	@Override
	public boolean shutdown(){
		
		return super.shutdown();
	}
	
	/**
	 * 
	 */
	public void init(){

		// 数据加载、计时器设定等等
		
		// 定时处理cache 
//		PlayerLazeProcTimer tt = new PlayerLazeProcTimer();
//		tt.setTimerOption(TaskTimer.LOOP);
//		tt.setInitialDelay(PROCESS_TIME);
//		tt.setPeriod(PROCESS_TIME);
//		tt.setCallback(this);
//		getModule().addTaskTimer(tt);
//		
//		PlayerCacheTimer tt2 = new PlayerCacheTimer();
//		tt2.setTimerOption(TaskTimer.LOOP);
//		tt2.setInitialDelay(PROCESS_TIME);
//		tt2.setPeriod(CACHE_PROCESS_TIME);
//		tt2.setCallback(this);
//		getModule().addTaskTimer(tt2);		
	}
	
	/**
	 * 
	 * @param info
	 * @param srcModuleID
	 */
	public int getPlayerListByGuid(BaseDataInfo info, String srcModuleID){
		
		if (info.getKey() == null) {
			return ResultNo.FAILED;
		}	
		
		GetPlayerListAsync loadData = new GetPlayerListAsync();
		loadData.setDataInfo(info);
		loadData.setDataManager(this);
		loadData.setSrcModuleID(srcModuleID);
		loadData.setCallback(this);
		
		// 异步处理
		addAsyncCommand(loadData);
		return ResultNo.PENDING;

	}
	
	/**
	 * 
	 * @param resultCode
	 * @param info
	 * @param srcModuleID
	 * @param obj
	 */
	public void getPlayerListCallback(int resultCode, BaseDataInfo info,
			String srcModuleID, Object obj){

		// info.setHandle(handle);
		info.setResultCode(resultCode);
//		info.setData(null);
		dataResponse(info, srcModuleID);
	}
	
	public int updateData(BaseDataInfo info, String srcModuleID, Object... userdata) {
		UpdatePlayerDataAsync task = new UpdatePlayerDataAsync();

		task.setDataManager(this);
		task.setDataInfo(info);
		task.setSrcModuleID((String) srcModuleID);
		task.setCallback(this);

		// 异步处理
		addAsyncCommand(task);
		return ResultNo.PENDING;
	}

	public int updateMoney(BasicServiceModule currentModule, BaseDataInfo info, String srcModuleID,
			Object... userdata) {
		UpdatePlayerMoneyAsync task = new UpdatePlayerMoneyAsync(null, currentModule);

		task.setDataInfo(info);
		task.setSrcModuleID(srcModuleID);
		task.setCallback(this);

		// 异步处理
		addAsyncCommand(task);
		return ResultNo.PENDING;
	}

	public int updateItem(BasicServiceModule currentModule, BaseDataInfo info, String srcModuleID,
			Object... userdata) {
		UpdatePlayerItemAsync task = new UpdatePlayerItemAsync(this, currentModule);

		task.setDataInfo(info);
		task.setSrcModuleID(srcModuleID);
		task.setCallback(this);

		// 异步处理
		addAsyncCommand(task);
		return ResultNo.PENDING;
	}
	
	public int updateMoneyItem(BasicServiceModule currentModule, BaseDataInfo info, String srcModuleID,
			Object... userdata) {
		UpdatePlayerMoneyItemAsync task = new UpdatePlayerMoneyItemAsync(this, currentModule);

		task.setDataInfo(info);
		task.setSrcModuleID(srcModuleID);
		task.setCallback(this);

		// 异步处理
		addAsyncCommand(task);
		return ResultNo.PENDING;
	}

	/**
	 * 
	 * @param key
	 * @param userdata
	 * @return
	 */
	public int readData(BaseDataInfo info, String srcModuleID,
			Object... userdata) {

		// 前面如果沒有return...就會走數據從DB讀取的流程
		LoadPlayerDataAsync loadData = new LoadPlayerDataAsync();

		loadData.setDataManager(this);
		loadData.setDataInfo(info);
		loadData.setSrcModuleID((String) srcModuleID);
		loadData.setCallback(this);

		// 异步处理
		addAsyncCommand(loadData);
		return ResultNo.PENDING;
	}

	/**
	 * 資料更新後，從DB回來會被調用的地方<br>
	 * @param resultCode
	 *            返回值、處理結果
	 * @param info
	 *            原本放到task的資料
	 * @param srcModuleID
	 *            請求人ID
	 * @param dataResponse
	 *            是否需要call dataResponse(..)
	 */
	public void updateDataCallback(int resultCode, BaseDataInfo info, String srcModuleID, boolean dataResponse) {
		if (resultCode == ResultNo.OK) {
			info.setDataSource(DataSource.DATABASE);
			info.setResultCode(resultCode);
			
			if (dataResponse) {
				dataResponse(info, srcModuleID);
			}
		} else {
			info.setResultCode(resultCode);
			
			if (dataResponse) {
				dataResponse(info, srcModuleID);
			}

			log.error("DB Load failed:" + info.getKey().toString());
		}
	}

	/**
	 * 變更玩家金錢後會 call 回來的地方
	 * 
	 * @param resultCode
	 *            返回值、處理結果
	 * @param info
	 *            原本放到task的資料
	 * @param srcModuleID
	 *            請求人ID
	 */
	public void updatePlayerMoneyToDbCallback(int resultCode, BaseDataInfo info, String srcModuleID) {
		if (resultCode == ResultNo.OK) {
			info.setDataSource(DataSource.DATABASE);
			info.setResultCode(resultCode);
			dataResponse(info, srcModuleID);
		} else {
			info.setResultCode(resultCode);
			dataResponse(info, srcModuleID);
			log.error("DB update money fail: " + info.getKey().toString());
		}
	}

	/**
	 * 變更玩家道具後會 call 回來的地方
	 * 
	 * @param resultCode
	 *            返回值、處理結果
	 * @param info
	 *            原本放到task的資料
	 * @param srcModuleID
	 *            請求人ID
	 */
	public void updatePlayerItemToDbCallback(int resultCode, BaseDataInfo info, String srcModuleID) {
		if (resultCode == ResultNo.OK) {
			info.setDataSource(DataSource.DATABASE);
			info.setResultCode(resultCode);
			dataResponse(info, srcModuleID);
		} else {
			info.setResultCode(resultCode);
			dataResponse(info, srcModuleID);
			log.error("DB update item fail: " + info.getKey().toString());
		}
	}
	
	/**
	 * 變更玩家金錢和道具後會 call 回來的地方
	 * 
	 * @param resultCode
	 *            返回值、處理結果
	 * @param info
	 *            原本放到task的資料
	 * @param srcModuleID
	 *            請求人ID
	 */
	public void updatePlayerMoneyItemToDbCallback(int resultCode, BaseDataInfo info, String srcModuleID) {
		if (resultCode == ResultNo.OK) {
			info.setDataSource(DataSource.DATABASE);
			info.setResultCode(resultCode);
			dataResponse(info, srcModuleID);
		} else {
			info.setResultCode(resultCode);
			dataResponse(info, srcModuleID);
			log.error("DB update money and item fail: " + info.getKey().toString());
		}
	}

	/**
	 * 從DB回來會被調用的地方<br>
	 * @param resultCode 返回值、處理結果
	 * @param info 原本放到task的資料
	 * @param srcModuleID 請求人ID
	 * @param obj 從DB撈回來的資料
	 * @param dataResponse 是否需要call dataResponse(..)
	 */
	public void readDataCallback(int resultCode, BaseDataInfo info,
			String srcModuleID, Object resultObj, boolean dataResponse) {		
		
		if(resultCode == ResultNo.OK && resultObj != null){
			info.setDataSource(DataSource.DATABASE);
			info.setResultCode(resultCode);
			info.setData(resultObj);

			if(dataResponse) dataResponse(info, srcModuleID);
		}
		else{			

			info.setResultCode(resultCode);
			if(dataResponse){
				dataResponse(info, srcModuleID);
			}
			if(log.isErrorEnabled()){
				if(info.getKey() != null){
					log.error("DB Load failed:" + info.getKey().toString() + " | ResultNo = " + resultCode + " | resultObj == null ? " + resultObj == null ? " true" : " false");
				}else{
					log.error("DB Load failed: info.getKey() == null " + " | ResultNo = " + resultCode + resultCode + " | resultObj == null ? " + resultObj == null ? " true" : " false", new RuntimeException());
				}
			}
			
		}

	}
	
	/**
	 * 創建玩家
	 * @param key
	 * @param userdata
	 * @return
	 */
	public int createData(BaseDataInfo info, String srcModuleID,
			Object... userdata){
		
		CreatePlayerDataAsync asyncTask = new CreatePlayerDataAsync();

		asyncTask.setDataManager(this);
		asyncTask.setDataInfo((PlayerData) info);
		asyncTask.setSrcModuleID((String) srcModuleID);
		asyncTask.setCallback(this);
		
		// 异步处理
		addAsyncCommand(asyncTask);
		return ResultNo.PENDING;
		
	}
	
	/**
	 * 從DB回來會被調用的地方<br>
	 * @param resultCode 返回值、處理結果
	 * @param info 原本放到task的資料
	 * @param srcModuleID 請求人ID
	 * @param obj 從DB撈回來的資料
	 */
	public void createDataCallback(int resultCode, BaseDataInfo info,
			String srcModuleID, Object resultObj) {		
		
		int handle = ERROR_HANDLE;
		
		if(resultCode == ResultNo.OK && resultObj != null){
			//cache 資料用
		}

		info.setHandle(handle);
		info.setResultCode(resultCode);
		info.setData(null);
		dataResponse(info, srcModuleID);
		
	}
	
	
	/**
	 * 加入異步處理依照key分配到固定的thread
	 * @param obj
	 * @return
	 */
	protected boolean addAsyncCommand(TaskAsyncCommand obj){
		
		if(obj == null){
			return false;
		}

		DCAsyncCommand cmd = (DCAsyncCommand)obj;
		GUID key = null;
		if(cmd.getDataInfo() != null) {
			key = cmd.getDataInfo().getKey();
		}
		if(key != null){
			int hash = key.hashCode() % GameUtility.getLastNIndex(getModule().asyncTaskQueueCount, 2);
			obj.setQueueID((hash < 0) ? -hash : hash);
		}
		return getModule().addAsyncCommand(obj);
	}
}
